package com.atguigu.gmall.service.config;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.common.entity.GmallCorrelationData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * @Author: 李旭
 * @Time: 15:20
 * @Description:
 *
 *    MQ
 *    producer生产者
 *    ack:应答
 *    config:配置类
 *
 */
@Component
@Slf4j
public class MQProducerAckConfig implements RabbitTemplate.ConfirmCallback
     ,RabbitTemplate.ReturnCallback{

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @PostConstruct //初始化注解
    public void MQProducerAckConfig(){
        this.rabbitTemplate.setConfirmCallback(this);
        this.rabbitTemplate.setReturnCallback(this);
    }

    //交换机应答方法   都要应答
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        //ack true:应答 成功   false : 应答 失败
        if(ack){
            log.info("交换机应答成功:" + cause);
        }else{
            log.info("交换机应答失败:" + cause);
            //重新发送刚才的这个消息
            retryMessage(correlationData);
        }
    }
    //重新发送消息
    private void retryMessage(CorrelationData correlationData) {
        GmallCorrelationData correlationData1 = (GmallCorrelationData) correlationData;

        //重新发送 3次  如果3次之后还是不成功  写日志
        int retryCount = correlationData1.getRetryCount();
        if(retryCount<3){
            retryCount++;
            correlationData1.setRetryCount(retryCount);
            log.info("重新发送消息" + retryCount + "次");
            //更新Redis缓存中的重新发送的次数
            String cacheKey = "mq:retry:message";
            redisTemplate.opsForHash().put(cacheKey,correlationData1.getId(),
                    JSONObject.toJSONString(correlationData1));//队列应答失败
            //重新发送
            rabbitTemplate.convertAndSend(correlationData1.getExchange(),
                    correlationData1.getRoutingKey(),correlationData1.getMessage(),
                    correlationData1);
        }else{
            log.error("重新发送消息3次了仍然失败的:" +
                    JSONObject.toJSONString(correlationData));
        }
    }

    //队列应答方法   只要失败了才应答
    @Override
    public void returnedMessage(Message message,
                                int replyCode,
                                String replyText,
                                String exchange,
                                String routingKey) {

        log.info("1队列失败应答：" + exchange + ":" + routingKey);
        log.info("2队列失败应答：" + replyCode + ":" + replyText);





        //MQ  1百万的消息    最头 小张  积压在MQ中出不来了  MQ OVER  外力 Redis
        Object uuid = message.getMessageProperties().
                getHeader("spring_returned_message_correlation");

        String cacheKey = "mq:retry:message";
        String json = (String) redisTemplate.
                opsForHash().get(cacheKey,uuid);

        GmallCorrelationData gmallCorrelationData = JSONObject.
                parseObject(json, GmallCorrelationData.class);

        //判断是基于插件的延迟消息  不要重新发送  真的把消息发丢了
        if(gmallCorrelationData.isChaJian()){
            System.out.println("基于插件的暂时就不重发了");
            return;
        }
        //重新发送
       retryMessage(gmallCorrelationData);
    }

    @Autowired
    private RedisTemplate redisTemplate;
}
